import 'dart:async';
import 'dart:convert';

import 'flutter_websocket_platform_interface.dart';

FlutterWebsocketPlatform? _lastwebSocketPlatform;

FlutterWebsocketPlatform get _webSocketPlatform {
  final FlutterWebsocketPlatform currentInstance =
      FlutterWebsocketPlatform.instance;
  if (_lastwebSocketPlatform != currentInstance) {
    _lastwebSocketPlatform = currentInstance;
  }
  return currentInstance;
}

enum WebsocketState {
  opening,
  opened,
  closing,
  closed,
}

class FlutterWebsocket {
  String? _id;

  String get id => _id!;

  StreamController? __controller;
  StreamController get _controller =>
      __controller ??= StreamController.broadcast();
  Stream get stream => _controller.stream;

  StreamController<WebsocketState>? __stateController;
  StreamController<WebsocketState> get _stateController =>
      __stateController ??= StreamController.broadcast();
  Stream<WebsocketState> get state => _stateController.stream;

  StreamSubscription? _subscription;

  WebsocketState _currentState = WebsocketState.closed;
  WebsocketState get currentState => _currentState;

  Future<void> connect(Uri uri) async {
    Completer completer = Completer();
    _id = await _webSocketPlatform.create(uri);

    _subscription = _webSocketPlatform
        .eventFor(id)
        .map((event) => Map<String, dynamic>.from(event))
        .listen(_handleIncoming, onError: _controller.addError);
    StreamSubscription? s;
    s = state.listen((event) {
      if (event == WebsocketState.opened) {
        completer.complete();
        s?.cancel();
      }
    }, onError: (e) {
      completer.completeError(e);
      s?.cancel();
    });

    await _webSocketPlatform.connect(id);
    return completer.future;
  }

  Future<void> send(List<int> data) => _webSocketPlatform.send(id, data);
  Future<void> sendText2(String text) => send(utf8.encode(text));
  Future<void> sendText(String text) => _webSocketPlatform.sendText(id, text);
  Future<void> close() async {
    await _webSocketPlatform.close(id);
    _subscription?.cancel();
    _subscription = null;
    __controller?.close();
    __controller = null;
    __stateController?.close();
    __stateController = null;
  }

  void _handleIncoming(Map<String, dynamic> data) {
    switch (data['event']) {
      case 'onState':
        _currentState = WebsocketState.values[data['data']];
        _stateController.add(_currentState);
        break;
      case 'onIncoming':
        _controller.add(data['data']);
        break;
    }
  }
}
